<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"
    />
    <title>策略模式-实现表单验证</title>
</head>
<style lang="css">
</style>

<body>
    <p>策略模式适用于：需要各种不同的规则，并且随时可替换规则，并且最终目的一致的场景，正如表单验证</p>
    <p>此处允许添加多条规则</p>

    <form id="registerForm">
        请输入用户名：
        <input type="text" name="userName" /> 请输入密码：
        <input type="text" name="password" /> 请输入手机号码：
        <input type="text" name="phoneNumber" />
        <button id="btn" type="button">提交</button>
    </form>

    <script type="text/javascript">
        var strategies = {
            isNonEmpty: function (value, errorMsg) {  // 不是空
                if (value === '') {
                    return errorMsg
                }
            },
            minLength: function (value, len, errorMsg) { // 最小长度
                if (value.length < len) {
                    return errorMsg
                }
            },
            isMobile: function (value, errorMsg) { // 是不是手机号
                if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
                    return errorMsg
                }
            }
        }
        var validatorFunc = function () {
            var validator = new Validator()
            /***************添加一些校验规则****************/
            validator.add(registerForm.userName, [{
                strategy: 'isNonEmpty',
                errorMsg: '用户名不能为空'
            }, {
                strategy: 'minLength:6',
                errorMsg: '用户名长度不能小于 10 位'
            }])
            validator.add(registerForm.password, [{
                strategy: 'isNonEmpty',
                errorMsg: '密码不能为空'
            }]) // 添加规则非常easy
            validator.add(registerForm.phoneNumber, [{
                strategy: 'isMobile',
                errorMsg: '手机号码格式不正确'
            }])

            var errorMsg = validator.start() // 返回校验结果
            return errorMsg
        }

        var Validator = function () {
            this.validateRules = []
        }

        Validator.prototype.add = function (dom, rules) {
            var self = this
            for (var i = 0, rule; i < rules.length; i++) {
                currentRule = rules[i]
                    ; (function (rule) {
                        var strategyAry = rule.strategy.split(':') // 把 strategy 和参数分开
                        var errorMsg = rule.errorMsg

                        self.validateRules.push(function () { // 把校验的步骤用空函数包装起来，并且放入 validateRules数组中，每一个元素都是一个方法
                            var strategy = strategyAry.shift() // 用户挑选的 strategy
                            strategyAry.unshift(dom.value) // 把 input 的 value 添加进参数列表
                            strategyAry.push(errorMsg) // 把 errorMsg 添加进参数列表

                            return strategies[strategy].apply(dom, strategyAry) // dom换成{}亦可
                        })
                    })(currentRule)
            }

        };

        Validator.prototype.start = function (value, stratergy, errorMsg) {

            for (var i = 0, validatorFunc; i < this.validateRules.length; i++) {

                validatorFunc = this.validateRules[i] // 将校验方法赋值给此处新建的变量validatorFunc

                var msg = validatorFunc() // 开始校验，并取得校验后的返回信息
                if (msg) { // 如果有确切的返回值，说明校验没有通过
                    return msg
                }
            }
        }

        var registerForm = document.getElementById('registerForm');
        var btn = document.querySelector('#btn')
        btn.addEventListener('click', function () {
            var errorMsg = validatorFunc() // 如果 errorMsg 有确切的返回值，说明未通过校验
            if (errorMsg) {
                alert(errorMsg)
                return false // 阻止表单提交
            }
            console.log('验证成功，提交')
        }, false)

    </script>

</body>

</html>